package com.dog.modules.file.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.dog.framework.core.exception.FileException;
import com.dog.modules.file.model.SysFileUploadVO;
import com.dog.modules.file.service.OssService;
import com.dog.modules.file.utils.FileUtils;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.util.Optional;

/**
 * @author haoxr
 * @since 2023/6/2
 */
@Component
@ConditionalOnProperty(value = "oss.type", havingValue = "minio")
@ConfigurationProperties(prefix = "oss.minio")
@RequiredArgsConstructor
@Data
public class MinioOssService implements OssService {

    /**
     * 服务Endpoint(http://localhost:9000)
     */
    private String endpoint;
    /**
     * 访问凭据
     */
    private String accessKey;
    /**
     * 凭据密钥
     */
    private String secretKey;
    /**
     * 存储桶名称
     */
    private String bucketName;
    /**
     * 自定义域名(https://oss.youlai.tech)
     */
    private String customDomain;

    private MinioClient minioClient;


    // 依赖注入完成之后执行初始化
    @PostConstruct
    public void init() {
        minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
    }

    /**
     * 上传文件
     *
     * @param file 表单文件对象
     * @return
     */
    @SneakyThrows
    @Override
    public SysFileUploadVO uploadFile(MultipartFile file) {
        SysFileUploadVO sysFileUploadVO = new SysFileUploadVO();
        String path = FileUtils.getPath(file.getOriginalFilename());
        try {
            //如果BucketName不存在，则创建
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!found) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
            String contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
            Optional<MediaType> mediaType = MediaTypeFactory.getMediaType(path);
            if (mediaType.isPresent()) {
                contentType = mediaType.get().toString();
            }
            minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).contentType(contentType).object(path).stream(file.getInputStream(), file.getInputStream().available(), -1).build());
        } catch (Exception e) {
            throw new FileException("上传文件失败：", e.getStackTrace());
        }

        String fileUrl = endpoint + "/" + bucketName + "/" + path;
        sysFileUploadVO.setUrl(fileUrl);
        sysFileUploadVO.setName(file.getOriginalFilename());
        sysFileUploadVO.setSize(file.getSize());
        sysFileUploadVO.setPlatform("minio");

        return sysFileUploadVO;
    }

    /**
     * 删除文件
     *
     * @param fileUrl 文件路径
     *                 https://oss.youlai.tech/default/20221120/test.jpg
     * @return
     */
    @SneakyThrows
    @Override
    public boolean deleteFile(String fileUrl) {
        Assert.notBlank(fileUrl, "删除文件路径不能为空");

        String fileName;
        if (StrUtil.isNotBlank(customDomain)) {
            // https://oss.youlai.tech/default/20221120/test.jpg → 20221120/test.jpg
            fileName = fileUrl.substring(customDomain.length() + 1 + bucketName.length() + 1); // 两个/占了2个字符长度
        } else {
            // http://localhost:9000/default/20221120/test.jpg → 20221120/test.jpg
            fileName = fileUrl.substring(endpoint.length() + 1 + bucketName.length() + 1);
        }
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build();

        minioClient.removeObject(removeObjectArgs);
        return true;
    }
}


